package cn.wenhao.javaClassReload.utils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * @title GenericsUtils
 * @desc 一些通用的工具方法
 * @author Rezar
 * @date 2015年9月13日
 * @version 1.0
 */
@Slf4j
public class GenericsUtils {

    /**
     * 判断某个对象是否为空或者如果是某些特殊对象的话，判断这些特殊对象的长度属性，是否为Empty
     * 
     * @param obj
     * @return
     */
    public static boolean notNullAndEmpty(Object obj) {

        if (obj == null) {
            return false;
        }

        if (obj instanceof String) {
            return ((String) obj).length() == 0 ? false : true;
        }

        if (obj instanceof Collection<?>) {
            return ((Collection<?>) obj).size() == 0 ? false : true;
        }

        if (obj instanceof Map<?, ?>) {
            return ((Map<?, ?>) obj).size() == 0 ? false : true;
        }

        Class<?> cla = obj.getClass();
        if (cla.isArray()) {
            return Array.getLength(obj) == 0 ? false : true;
        }

        return true;

    }

    public static boolean isNullOrEmpty(Object obj) {
        return !notNullAndEmpty(obj);
    }

    /**
     * 判断一个对象中的某个属性是否为普通的属性，且判断该属性是否为默认值
     * 
     * @param field
     * @param qm
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static boolean isNotNull(Field field, Object qm) throws IllegalArgumentException, IllegalAccessException {
        boolean notNull = true;
        Class<?> type = field.getType();
        if (type == int.class) {
            notNull = ((Integer) field.get(qm) == 0 ? false : true);
        }
        if (type == double.class) {
            notNull = ((Double) field.get(qm) == 0.0 ? false : true);
        }
        if (type == float.class) {
            notNull = ((Float) field.get(qm) == 0.0 ? false : true);
        }
        if (type == boolean.class) {
            notNull = ((Boolean) field.get(qm) == false ? false : true);
        }
        if (type == char.class) {
            notNull = ((Character) field.get(qm) == '\u0000' ? false : true);
        }
        if (type == byte.class) {
            notNull = ((Byte) field.get(qm) == 0 ? false : true);
        }
        if (type == short.class) {
            notNull = ((Short) field.get(qm) == 0 ? false : true);
        }
        return notNull;
    }

    public static boolean notEqualsIn(String value, boolean ignoreCase, String...strs) {
        boolean isIn = false;
        for (int i = 0; i < strs.length; i++) {
            if (ignoreCase) {
                isIn = strs[i].equals(value);
            } else {
                isIn = strs[i].equalsIgnoreCase(value);
            }
        }
        return isIn;
    }

    /**
     * 从一个字符串中找到某个字符串出现的位置，从指定开始的位置开始查找
     * 
     * @param str
     * @return
     */
    public static int indexOfIgnoreCase(String str, int fromIndex) {

        str = str.toLowerCase();
        return str.indexOf(str, fromIndex);

    }

    public static StringBuilder deleteLastChar(StringBuilder sb) {
        if (sb != null && sb.length() > 0) {
            return sb.deleteCharAt(sb.length() - 1);
        } else {
            return sb;
        }
    }

    public static String deleteLastCharToString(StringBuilder sb) {
        return deleteLastChar(sb).toString();
    }

    public static <T extends Collection<K>, K> List<K> toList(T cols) {
        return new ArrayList<K>(cols);
    }

    @SuppressWarnings("unchecked")
    public static <K, V> List<K> toKeyList(Collection<? extends V> cols, String field) {
        if (isNullOrEmpty(cols)) {
            return Collections.emptyList();
        }
        List<K> retList = new ArrayList<K>();
        try {
            Class<?> beanClass = cols.toArray()[0].getClass();
            final PropertyDescriptor pd = new PropertyDescriptor(field, beanClass);
            for (V value : cols) {
                try {
                    retList.add((K) pd.getReadMethod().invoke(value, new Object[] {}));
                } catch (Exception e) {
                    log.debug("encount a error cause by : {} ", e);
                }
            }
        } catch (Exception ex) {
            log.error("exception : {} ", ex);
        }
        return retList;
    }

    public static void setAccessable(String fieldName, Class<?> beanClass) {
        try {
            Field field = beanClass.getDeclaredField(fieldName);
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
        } catch (Exception e) {
            log.debug("can not set accessible for field : {} in class : {} ", fieldName, beanClass);
        }
    }

    /**
     * 添加这个方法的原因:<br/>
     * 因为之前都是调用 , Collections.emptyList(); ,<br/>
     * 这个方法会返回一个EmptyList对象，该对象继承AbstractList父类 其add方法未实现.<br/>
     * 所以在使用底层方法返回的Collections.emptyList() 对象再添加新数据的时候，会报 java.lang.UnsupportedOperationException
     * 
     * @return
     */
    public static <T> List<T> emptyList() {
        return Lists.newArrayListWithCapacity(0);
    }

    /**
     * @see GenericsUtils.emptyList()
     * @return
     */
    public static <K, V> Map<K, V> emptyMap() {
        return Maps.newHashMapWithExpectedSize(0);
    }

    /**
     * @see GenericsUtils.emptyList()
     * @return
     */
    public static <T> Set<T> emptySet() {
        return Sets.newHashSetWithExpectedSize(0);
    }

    /**
     * @param emptyMap
     * @param key
     * @param listValue
     */
    public static <K, V> void addListIfNotExists(Map<K, List<V>> map, K key, V listValue) {
        List<V> list = map.get(key);
        if (isNullOrEmpty(list)) {
            list = Lists.newArrayList();
            map.put(key, list);
        }
        list.add(listValue);
    }

    private static final String COMMON_SPLIT_RETEX = "[,|:&#]+";

    public static <T> Set<T> stringToNumber(String numStr, Class<T> numType) {
        return stringToNumber(numStr, COMMON_SPLIT_RETEX, numType);
    }

    @SuppressWarnings("unchecked")
    public static <T> Set<T> stringToNumber(String numStr, String splitRegex, Class<T> numType) {
        if (GenericsUtils.isNullOrEmpty(numStr)) {
            return emptySet();
        }

        String[] allValues = numStr.split(splitRegex);
        Set<T> retSet = Sets.newHashSet();
        for (String value : allValues) {
            Object numValue = getNumValueFromStr(numType, value);
            retSet.add((T) numValue);
        }
        return retSet;
    }

    /**
     * @param numType
     * @param value
     * @return
     */
    public static <T> Object getNumValueFromStr(Class<T> numType, String value) {
        Object numValue = null;
        if (numType == Integer.class || numType == int.class) {
            numValue = Integer.parseInt(value);
        } else if (numType == Float.class || numType == float.class) {
            numValue = Float.parseFloat(value);
        } else if (numType == Long.class || numType == long.class) {
            numValue = Long.parseLong(value);
        } else if (numType == Double.class || numType == double.class) {
            numValue = Double.parseDouble(value);
        } else if (numType == Byte.class || numType == byte.class) {
            numValue = Byte.parseByte(value);
        } else if (numType == Character.class || numType == char.class) {
            numValue = new Character(value.charAt(0));
        }
        return numValue;
    }

}
